/**
 * 
 */
package cn.edu.nju.ws.sview.wyge.relations.adataset.entities;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import org.apache.lucene.util.TwoPhaseCommitTool.PrepareCommitFailException;
import org.json.simple.JSONObject;

import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.database.DBConnectionFactory;
import cn.edu.nju.ws.sview.wyge.relations.adataset.CustomDataset;
import cn.edu.nju.ws.sview.wyge.relations.adataset.entities.qxliu.algorithms.ClassTree;

/**
 * @author Weiyi Ge (geweiyi@gmail.com) 2012-7-28
 * 
 */
public class GetNamedEntities {
	
	public static void main(String[] argus) {
		ArrayList<ISentence> res = find("uri", 49417894);
		for (ISentence s : res) {
			System.out.println(s.getTriples());
		}
	}
	public static HashMap<Integer, ArrayList<String>> assortEntities(String ds_type, int ds_id){
		ArrayList<Integer> docs = null;
		if (ds_type.equals("custom")) {
			docs = CustomDataset.getURLIDsByCustomDatasetId(ds_id);
		} else if (ds_type.equals("uri")) {
			docs = new ArrayList<Integer>();
			docs.add(ds_id);
		}
		return assortEntities(docs);
	}
	public static ArrayList<String> findEntityIds(String ds_type, int ds_id){
		ArrayList<Integer> docs = null;
		if (ds_type.equals("custom")) {
			docs = CustomDataset.getURLIDsByCustomDatasetId(ds_id);
		} else if (ds_type.equals("uri")) {
			docs = new ArrayList<Integer>();
			docs.add(ds_id);
		}
		return findEntityIds(docs);
	}
	public static ArrayList<ISentence> findNoTyped(String ds_type, int ds_id, String showedSub){
		ArrayList<Integer> docs = null;
		if (ds_type.equals("custom")) {
			docs = CustomDataset.getURLIDsByCustomDatasetId(ds_id);
		} else if (ds_type.equals("uri")) {
			docs = new ArrayList<Integer>();
			docs.add(ds_id);
		}
		return findNoTyped(docs,showedSub);
	}
	public static ArrayList<ISentence> find(String ds_type, int ds_id) {
		ArrayList<Integer> docs = null;
		if (ds_type.equals("custom")) {
			docs = CustomDataset.getURLIDsByCustomDatasetId(ds_id);
		} else if (ds_type.equals("uri")) {
			docs = new ArrayList<Integer>();
			docs.add(ds_id);
		}
//		System.out.println("docs:"+docs.size());
		return find(docs);
	}
	/**
	 * assort entities by their minimal classes
	 * @param docs
	 * @return class->entities
	 */
	public static HashMap<Integer, ArrayList<String>> assortEntities(ArrayList<Integer> docs){
		HashMap<Integer, ArrayList<String>> assortMap = new HashMap<Integer, ArrayList<String>>();
		ArrayList<String> eids = GetNamedEntities.findEntityIds(docs);
		for(String subject : eids){
			HashSet<Integer> minClasses = ClassFinder.getMinClass(docs, subject);
			for(Integer cid : minClasses){
				ArrayList<String> instances = null;
				if(assortMap.containsKey(cid)){
					instances = assortMap.get(cid);
					instances.add(subject);
					
				}else{
					instances = new ArrayList<String>();
					instances.add(subject);
				}
				assortMap.put(cid, instances);
			}
			if(minClasses==null || minClasses.size()==0){
				ArrayList<String> instances = null;
				if(assortMap.containsKey(0)){
					instances = assortMap.get(0);
					instances.add(subject);
					
				}else{
					instances = new ArrayList<String>();
					instances.add(subject);
				}
				assortMap.put(0, instances);
			}
		}
		
		return assortMap;
	}
	
	/**
	 * 
	 * @param docs
	 * @return "u"+id list of subjects of sentences
	 */
	public static ArrayList<String> findEntityIds(ArrayList<Integer> docs){
		ArrayList<String> ids = new ArrayList<String>();

		String docstring = "";
		for (int doc : docs) {
			docstring += doc + ",";
		}
		docstring = docstring.substring(0, docstring.length() - 1);
		try {
			Connection con = DBConnectionFactory.getConnection();// .getFalconConnection();
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery(String.format(
					"SELECT distinct s FROM quadruple where doc_id in (%s)",
					docstring)
					+ " and s like 'u%'");// 主语为uri
			while (rs.next()) {
				ids.add(rs.getString(1));
			}
			rs.close();
			stmt.close();
			con.close();

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ids;
	}
	
	/**
	 * 
	 * @param docs
	 *            文檔
	 * @param classes
	 *            被實例化的classes以及他們的子類
	 * @return
	 */
	private static ArrayList<ISentence> findNoTyped(ArrayList<Integer> docs, String showedSub) {
		ArrayList<ISentence> res = new ArrayList<ISentence>();

		String docstring = "";
		for (int doc : docs) {
			docstring += doc + ",";
		}
		docstring = docstring.substring(0, docstring.length() - 1);
		try {
			HashSet<String> subjects = new HashSet<String>();
			Connection con = DBConnectionFactory.getConnection();// .getFalconConnection();
			Statement stmt = con.createStatement();
			String andSql = "";
			if(showedSub.length()>0){
				andSql = " and s not in ("+showedSub+") ";
			}
			ResultSet rs = stmt.executeQuery(String.format(
					"SELECT distinct s FROM quadruple where doc_id in (%s)",
					docstring)
					+ " and s like 'u%'"
					+ andSql);// 主语为uri,且尚未显示
			while (rs.next()) {
				subjects.add(rs.getString(1));
			}
			rs.close();
			stmt.close();

			String s_string = "";
			for (String subject : subjects) {
				s_string += "\"" + subject + "\",";
			}
			if(s_string.length()>0){
				s_string = s_string.substring(0, s_string.length() - 1);
				s_string = " and s in ("+s_string+")";
			}

			HashMap<String, ISentence> sents = new HashMap<String, ISentence>();
			String selsentstring = String
					.format("SELECT distinct s, sentence_hash, doc_id FROM quadruple where doc_id in (%s) "+s_string,
							docstring, s_string);
			Statement selsentstmt = con.createStatement();
			ResultSet selsentrs = selsentstmt.executeQuery(selsentstring);
			while (selsentrs.next()) {
				String s = selsentrs.getString(1);
				byte[] sent = selsentrs.getBytes(2);
				int c = selsentrs.getInt(3);
				if (subjects.contains(s)) {
					if (sents.containsKey(s)) {
						ISentence is = sents.get(s);
						is.addSent(c, sent);
					} else {
						ISentence is = new ISentence(s);
						is.addSent(c, sent);
						sents.put(s, is);
					}
				}
			}
			selsentrs.close();
			selsentstmt.close();
			con.close();

			for (ISentence is : sents.values()) {
				res.add(is);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return res;
	}
	/**
	 * 
	 * @param docs
	 *            文檔
	 * @param classes
	 *            被實例化的classes以及他們的子類
	 * @return
	 */
//	private static ArrayList<ISentence> find(ArrayList<Integer> docs) {
	public static ArrayList<ISentence> find(ArrayList<Integer> docs) {
		ArrayList<ISentence> res = new ArrayList<ISentence>();

		String docstring = "";
		for (int doc : docs) {
			docstring += doc + ",";
		}
		docstring = docstring.substring(0, docstring.length() - 1);
		try {
			HashSet<String> subjects = new HashSet<String>();
			Connection con = DBConnectionFactory.getConnection();// .getFalconConnection();
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery(String.format(
					"SELECT distinct s FROM quadruple where doc_id in (%s)",
					docstring)
					+ " and s like 'u%'");// 主语为uri
			while (rs.next()) {
				subjects.add(rs.getString(1));
			}
			rs.close();
			stmt.close();

			String s_string = "";
			for (String subject : subjects) {
				s_string += "\"" + subject + "\",";
			}
			if(s_string.length()>0){
//				s_string = s_string.substring(0, s_string.length() - 1);
				s_string = s_string.substring(0, s_string.lastIndexOf(","));
				s_string = " and s in ("+s_string+")";
				
			}

			HashMap<String, ISentence> sents = new HashMap<String, ISentence>();
			String selsentstring = String
					.format("SELECT distinct s, sentence_hash, doc_id FROM quadruple where doc_id in (%s) %s",// and s in (%s)",
							docstring, s_string);
			Statement selsentstmt = con.createStatement();
			ResultSet selsentrs = selsentstmt.executeQuery(selsentstring);
			while (selsentrs.next()) {
				String s = selsentrs.getString(1);
				byte[] sent = selsentrs.getBytes(2);
				int c = selsentrs.getInt(3);
				if (subjects.contains(s)) {
					if (sents.containsKey(s)) {
						ISentence is = sents.get(s);
						is.addSent(c, sent);
					} else {
						ISentence is = new ISentence(s);
						is.addSent(c, sent);
						sents.put(s, is);
					}
				}
			}
			selsentrs.close();
			selsentstmt.close();
			con.close();

			for (ISentence is : sents.values()) {
				res.add(is);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return res;
	}
	public static ArrayList<String> findEntityIds(String ds_type, int ds_id, int classid){
		ArrayList<Integer> docs = null;
		if (ds_type.equals("custom")) {
			docs = CustomDataset.getURLIDsByCustomDatasetId(ds_id);
		} else if (ds_type.equals("uri")) {
			docs = new ArrayList<Integer>();
			docs.add(ds_id);
		}
		ClassTree ct = new ClassTree(ds_type, ds_id);
		ArrayList<Integer> clses = ct.getChildren(classid);//===========
		clses.add(classid);
		return findEntityIds(docs, clses);
		
	}
	public static ArrayList<ISentence> findIdentical(String ds_type, int ds_id,
			int classid) {
		ArrayList<Integer> docs = null;
		if (ds_type.equals("custom")) {
			docs = CustomDataset.getURLIDsByCustomDatasetId(ds_id);
		} else if (ds_type.equals("uri")) {
			docs = new ArrayList<Integer>();
			docs.add(ds_id);
		}
		ClassTree ct = new ClassTree(ds_type, ds_id);
		ArrayList<Integer> children = ct.getChildren(classid);//===========
		return findIdentical(docs, classid, children);
	}
	
	public static ArrayList<ISentence> find(String ds_type, int ds_id, int classid) {
		ArrayList<Integer> docs = null;
		if (ds_type.equals("custom")) {
			docs = CustomDataset.getURLIDsByCustomDatasetId(ds_id);
		} else if (ds_type.equals("uri")) {
			docs = new ArrayList<Integer>();
			docs.add(ds_id);
		}
		ClassTree ct = new ClassTree(ds_type, ds_id);
		ArrayList<Integer> clses = ct.getChildren(classid);//===========
		clses.add(classid);
		return find(docs, clses);
	}
	public static ArrayList<String> findEntityIds(ArrayList<Integer> docs, ArrayList<Integer> classes) {
		ArrayList<String> eids = new ArrayList<String>();

		String docstring = "";
		for (int doc : docs) {
			docstring += doc + ",";
		}
		docstring = docstring.substring(0, docstring.length() - 1);
		String ostring = "";
		for (int cls : classes) {
			ostring += "\"u" + cls + "\",";
		}
		ostring = ostring.substring(0, ostring.length() - 1);
		try {
			Connection con = DBConnectionFactory.getConnection();// .getFalconConnection();
			Statement stmt = con.createStatement();
			int typeid = 0;
			try {
				typeid = URIIDCache.getInstance().getURIID(
						"http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
						false);
			} catch (Throwable e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			ResultSet rs = stmt.executeQuery(String.format(
					"SELECT distinct s FROM quadruple where doc_id in (%s)",
					docstring)
					+ " and s like 'u%' and p='u"
					+ typeid
					+ "' and o in ("
					+ String.format("%s", ostring) + ")");// 主语为uri
			while (rs.next()) {
				eids.add(rs.getString(1));
			}
			rs.close();
			stmt.close();
			con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return eids;
		
	}
	/**
	 * 
	 * @param docs
	 *            文檔
	 * @param classId
	 *            被實例化的class
	 * @return sentences whose subject only belongs to classId and not belongs to the class's child
	 */
	private static ArrayList<ISentence> findIdentical(ArrayList<Integer> docs,
			int classId, ArrayList<Integer> children) {
		ArrayList<ISentence> res = new ArrayList<ISentence>();
		String docstring = "";
		for (int doc : docs) {
			docstring += doc + ",";
		}
		docstring = docstring.substring(0, docstring.length() - 1);
		String exclueStr = "";
		for (int cls : children) {
			exclueStr += "\"u" + cls + "\",";
		}
		if(exclueStr.contains(",")){
			exclueStr = exclueStr.substring(0, exclueStr.length() - 1);
		}
		try {
			HashSet<String> csubjects = new HashSet<String>();
			HashSet<String> esubjects = new HashSet<String>();
			Connection con = DBConnectionFactory.getConnection();// .getFalconConnection();
			int typeid = 0;
			try {
				typeid = URIIDCache.getInstance().getURIID(
						"http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
						false);
			} catch (Throwable e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			if(exclueStr.length()>0){
				Statement estmt = con.createStatement();
				ResultSet ers = estmt.executeQuery(String.format(
						"SELECT distinct s FROM quadruple where doc_id in (%s)",
						docstring)
						+ " and s like 'u%' and p='u"
						+ typeid
						+ "' and o in ("
						+ String.format("%s", exclueStr) + ")");// 主语为uri
				while (ers.next()) {
					esubjects.add(ers.getString(1));
				}
				ers.close();
				estmt.close();
			}
			String estr = "";
			if(esubjects.size()>0){
				estr = " and s not in (";
				for(String esub : esubjects){
					estr += "'"+esub + "',";
				}
				if(estr.contains(",")){
					estr = estr.substring(0, estr.length()-1);
				}
				estr += ") ";
			}
			Statement cstmt = con.createStatement();
			ResultSet crs = cstmt.executeQuery(String.format(
					"SELECT distinct s FROM quadruple where doc_id in (%s)",
					docstring)
					+ " and s like 'u%' and p='u"
					+ typeid
					+ "' and o ='u"+classId+"'"
					+ estr);// 主语为uri
			while (crs.next()) {
				String sub = crs.getString(1);
//				if(!esubjects.contains(sub)){
					csubjects.add(sub);
//				}
			}
			crs.close();
			cstmt.close();
			String s_string = "";
			if (csubjects.size() > 0) {
				for (String subject : csubjects) {
					s_string += "\"" + subject + "\",";
				}
				s_string = s_string.substring(0, s_string.length() - 1);
			}

			HashMap<String, ISentence> sents = new HashMap<String, ISentence>();
			String selsentstring = String
					.format("SELECT distinct s, sentence_hash, doc_id FROM quadruple where doc_id in (%s) and s in (%s)",
							docstring, s_string);
			Statement selsentstmt = con.createStatement();
			ResultSet selsentrs = selsentstmt.executeQuery(selsentstring);
			while (selsentrs.next()) {
				String s = selsentrs.getString(1);
				byte[] sent = selsentrs.getBytes(2);
				int c = selsentrs.getInt(3);
				if (csubjects.contains(s)) {
					if (sents.containsKey(s)) {
						ISentence is = sents.get(s);
						is.addSent(c, sent);
					} else {
						ISentence is = new ISentence(s);
						is.addSent(c, sent);
						sents.put(s, is);
					}
				}
			}
			selsentrs.close();
			selsentstmt.close();
			con.close();
			for (ISentence is : sents.values()) {
				res.add(is);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return res;
	}
	/**
	 * 
	 * @param docs
	 *            文檔
	 * @param classes
	 *            被實例化的classes以及他們的子類
	 * @return
	 */
	public static ArrayList<ISentence> find(ArrayList<Integer> docs,
			ArrayList<Integer> classes) {//private
		ArrayList<ISentence> res = new ArrayList<ISentence>();

		String docstring = "";
		for (int doc : docs) {
			docstring += doc + ",";
		}
		docstring = docstring.substring(0, docstring.length() - 1);
		String ostring = "";
		for (int cls : classes) {
			ostring += "\"u" + cls + "\",";
		}
		ostring = ostring.substring(0, ostring.length() - 1);
		try {
			HashSet<String> subjects = new HashSet<String>();
			Connection con = DBConnectionFactory.getConnection();// .getFalconConnection();
			Statement stmt = con.createStatement();
			int typeid = 0;
			try {
				typeid = URIIDCache.getInstance().getURIID(
						"http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
						false);
			} catch (Throwable e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			ResultSet rs = stmt.executeQuery(String.format(
					"SELECT distinct s FROM quadruple where doc_id in (%s)",
					docstring)
					+ " and s like 'u%' and p='u"
					+ typeid
					+ "' and o in ("
					+ String.format("%s", ostring) + ")");// 主语为uri
			while (rs.next()) {
				subjects.add(rs.getString(1));
			}
			rs.close();
			stmt.close();

			String s_string = "";
			if (subjects.size() > 0) {
				for (String subject : subjects) {
					s_string += "\"" + subject + "\",";
				}
				s_string = s_string.substring(0, s_string.length() - 1);
			}

			HashMap<String, ISentence> sents = new HashMap<String, ISentence>();
			String selsentstring = String
					.format("SELECT distinct s, sentence_hash, doc_id FROM quadruple where doc_id in (%s) and s in (%s)",
							docstring, s_string);
			Statement selsentstmt = con.createStatement();
			ResultSet selsentrs = selsentstmt.executeQuery(selsentstring);
			while (selsentrs.next()) {
				String s = selsentrs.getString(1);
				byte[] sent = selsentrs.getBytes(2);
				int c = selsentrs.getInt(3);
				if (subjects.contains(s)) {
					if (sents.containsKey(s)) {
						ISentence is = sents.get(s);
						is.addSent(c, sent);
					} else {
						ISentence is = new ISentence(s);
						is.addSent(c, sent);
						sents.put(s, is);
					}
				}
			}
			selsentrs.close();
			selsentstmt.close();
			con.close();
			for (ISentence is : sents.values()) {
				res.add(is);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return res;
	}
}
